package priv.pfz.basedao.query;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.StrSubstitutor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author yyjxp
 * 2024/1/28 20:13
 */
@Getter
public class BaseQuery<Query extends BaseQuery<Query>> {

    /**
     * 参数
     */
    private final List<Object> v = Lists.newArrayList();

    /**
     * 占位符，默认为?
     * v1\v2...对应where占位符
     * offset\rows对应limit占位符
     */
    private final Map<String, String> placeholderMap = Maps.newHashMap();

    /**
     * where
     */
    private final List<Condition<?>> conditions = new ArrayList<>();

    /**
     * order by
     */
    protected List<String> orderBys = new ArrayList<>();

    /**
     * limit
     */
    private String limitSqlFormat;
    private List<Integer> limitArgs;
    private int pageNo;
    private int pageSize;
    private int offset;
    private int rows;

    /**
     * 增加一个value，返回value占位符对应的key
     */
    String addValue(Object value) {
        int index = v.size();
        v.add(value);
        placeholderMap.put("v" + index, "?");
        return "${v" + index + "}";
    }

    void addCondition(Condition<?> condition) {
        conditions.add(condition);
    }

    public void overrideMyBatisPlaceholder(String argName) {
        if (StringUtils.isBlank(argName)) {
            for (int i = 0; i < v.size(); i++) {
                placeholderMap.put("v" + i, "#{v[" + i + "]}");
            }
            placeholderMap.put("offset", "#{offset}");
            placeholderMap.put("rows", "#{rows}");
        } else {
            for (int i = 0; i < v.size(); i++) {
                placeholderMap.put("v" + i, "#{" + argName + ".v[" + i + "]}");
            }
            placeholderMap.put("offset", "#{" + argName + "." + "offset}");
            placeholderMap.put("rows", "#{" + argName + "." + "rows}");
        }
    }

    public String[] getConditionSql() {
        StrSubstitutor strSubstitutor = new StrSubstitutor(placeholderMap);
        return conditions.stream().map(c -> strSubstitutor.replace(c.getSqlFormat())).toArray(String[]::new);
    }

    public boolean hasLimit() {
        return StringUtils.isNotBlank(limitSqlFormat);
    }

    public String getLimitSql() {
        return new StrSubstitutor(placeholderMap).replace(limitSqlFormat);
    }

    public List<Integer> getLimitArgs() {
        return limitArgs;
    }

    public String[] getOrderBySqls() {
        return orderBys.toArray(new String[0]);
    }

    /**
     * 增加分页参数
     * LIMIT (pageNo-1)*pageSize, pageSize
     */
    public Query page(int pageNo, int pageSize) {
        this.pageNo = pageNo;
        this.pageSize = pageSize;
        this.offset = (pageNo - 1) * pageSize;
        this.rows = pageSize;
        this.limitSqlFormat = "${offset}" + ", " + "${rows}";
        this.placeholderMap.put("offset", "?");
        this.placeholderMap.put("rows", "?");
        this.limitArgs = Lists.newArrayList(offset, rows);
        return (Query) this;
    }

    /**
     * LIMIT offset, rows
     */
    public Query limit(int offset, int rows) {
        this.offset = offset;
        this.rows = rows;
        this.limitSqlFormat = "${offset}" + ", " + "${rows}";
        this.placeholderMap.put("offset", "?");
        this.placeholderMap.put("rows", "?");
        this.limitArgs = Lists.newArrayList(offset, rows);
        return (Query) this;
    }

    /**
     * LIMIT rows
     */
    public Query limit(int rows) {
        this.rows = rows;
        this.limitSqlFormat = "${rows}";
        this.placeholderMap.put("rows", "?");
        this.limitArgs = Lists.newArrayList(rows);
        return (Query) this;
    }
}
